package com.chitang.client;

import com.chitang.handler.ClientWebsocketHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.net.URI;
import java.util.concurrent.TimeUnit;

/**
 * @Author: wjs
 * @CreateTime: 2023-03-10 17:03
 */
@Slf4j
@Component
public class NettyClient implements ApplicationRunner {

    private final String URI = "ws://127.0.0.1:5429/chitang?id=100";


    public void connect() throws Exception {
        NioEventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.TCP_NODELAY, true)
                .group(group)
                .handler(new LoggingHandler(LogLevel.INFO))
                .channel(NioSocketChannel.class)
                .handler(new ClientChannelInitializer());
        URI uri = new URI(URI);
        DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();
        log.info("开始连接服务器...");
        // 进行握手
        WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(uri, WebSocketVersion.V13, null, true, httpHeaders);
        // 客户端与服务器连接的通道，final修饰表示只有一个
        ChannelFuture channelFuture = null;
        try {
            channelFuture = bootstrap.connect(uri.getHost(), uri.getPort()).sync();
        } catch (Exception e) {
            log.error("连接服务器异常：{}，正在重连...", e.getMessage());
            e.printStackTrace();
            final EventLoop loop = group.next();
            loop.schedule(new ReconnectionSchedule(), 3, TimeUnit.SECONDS);
            return;
        }
        final Channel channel = channelFuture.channel();
        ClientWebsocketHandler handler = (ClientWebsocketHandler) channel.pipeline().get("clientWebsocketHandler");
        handler.setHandshaker(handshaker);
        handshaker.handshake(channel);
        //阻塞等待是否握手成功
        handler.handshakeFuture().sync();
        System.out.println("握手成功");
    }

    /**
     * 重连线程类
     */
    class ReconnectionSchedule implements Runnable {
        @Override
        public void run() {
            try {
                connect();
            } catch (Exception e1) {
                throw new RuntimeException(e1);
            }
        }
    }

    public void sendMessage(Channel channel) {
        //发送的内容，是一个文本格式的内容
        String putMessage = "你好，我是客户端";
        TextWebSocketFrame frame = new TextWebSocketFrame(putMessage);
        channel.writeAndFlush(frame).addListener(new ChannelFutureListener() {
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()) {
                    System.out.println("消息发送成功，发送的消息是：" + putMessage);
                } else {
                    System.out.println("消息发送失败 " + channelFuture.cause().getMessage());
                }
            }
        });
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        connect();
    }
}
